import { Injectable, InternalServerErrorException } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import { DataSource, FindOneOptions, In, IsNull, Repository, TreeRepository } from 'typeorm'
import { PAGENATION } from '@/constants/pagenation.constants'
import { Menu } from '@/entities/menu.entity'
import { Permission } from '@/entities/permission.entity'
import { formatMenuWithButtons, sortMenuByOrder } from '@/utils/formatMenu'
import { CreateMenuDto } from './dto/create-menu.dto'
import { UpdateMenuDto } from './dto/update-menu.dto'
@Injectable()
export class MenuService {
  constructor(
    @InjectRepository(Menu)
    private readonly menuRepository: TreeRepository<Menu>,
    @InjectRepository(Permission)
    private readonly permissionRepository: Repository<Permission>,
    private dataSource: DataSource
  ) {}
  async create(createMenuDto: CreateMenuDto) {
    if (!createMenuDto.parentId) {
      createMenuDto.parentId = null
    }
    const menu = this.menuRepository.create(createMenuDto)
    if (createMenuDto.buttons?.length > 0) {
      menu.permissions = []
      createMenuDto.buttons.forEach((button) => {
        const permisssion = new Permission()
        permisssion.permissionCode = button.code
        permisssion.permissionDesc = button.desc
        menu.permissions.push(this.permissionRepository.create(permisssion))
      })
    }
    if (createMenuDto.parentId) {
      const parent = await this.findOneById(createMenuDto.parentId)
      menu.parent = parent
    }
    return this.menuRepository.save(menu)
  }

  findAll(options: FindOneOptions<Menu> = null) {
    return this.menuRepository.find(options)
  }

  findAllAsTrees() {
    return this.menuRepository.findTrees({
      relations: ['roles'],
    })
  }

  async findAllAsTreesAndCount(query, options: FindOneOptions<Menu> = null) {
    const { current = PAGENATION.current, size = PAGENATION.size, ...rest } = query
    const take = size // 条数
    const skip = (current - 1) * take // 页码 - 要跳过多少条
    const params: FindOneOptions<Menu> = {
      where: {
        parentId: IsNull(),
        ...rest,
      },
      order: {
        order: 'ASC',
      },
    }
    if (options) {
      for (const key in options) {
        params[key] = options[key]
      }
    }
    const [records, total] = await this.menuRepository.findAndCount({
      ...params,
      take,
      skip,
    })
    for (let i = 0; i < records.length; i++) {
      let item = records[i]
      if (!item.parentId) {
        item.parentId = null
      }
      item = await this.menuRepository.findDescendantsTree(item, {
        relations: ['permissions'],
      })
      item.children = sortMenuByOrder(item.children)
    }
    return {
      records: formatMenuWithButtons(records),
      total,
      current,
      size,
    }
  }

  findOneById(id: string) {
    return this.menuRepository.findOne({
      where: { id },
      relations: ['permissions'],
    })
  }

  findOneByRouteName(routeName: string) {
    return this.menuRepository.findOne({
      where: { routeName },
      relations: ['roles'],
    })
  }

  async update(id: string, updateMenuDto: UpdateMenuDto, operatorUser?: PayloadUserType) {
    const menu = await this.findOneById(id)

    const { buttons = [], parentId, ...rest } = updateMenuDto
    console.log('parentId', parentId)
    const params: Menu = {
      ...menu,
      ...rest,
    }

    const queryRunner = this.dataSource.createQueryRunner()
    try {
      await queryRunner.connect()
      await queryRunner.startTransaction()
      await queryRunner.manager.save(this.menuRepository.create(params))
      const deleteIds = menu.permissions
        .filter(
          (permissionItem) =>
            !buttons.map((buttonItem) => buttonItem.code).includes(permissionItem.permissionCode)
        )
        .map((result) => result.id)

      if (deleteIds.length) {
        await queryRunner.manager.delete(Permission, deleteIds)
      }

      const insertPermissions = buttons.filter((buttonItem) => {
        return !menu.permissions
          .map((permissionItem) => permissionItem.permissionCode)
          .includes(buttonItem.code)
      })
      console.log('insertPermissions', insertPermissions)

      if (insertPermissions.length) {
        const permisssionEntity = []
        for (const permission of insertPermissions) {
          const tempPermission = new Permission()
          tempPermission.permissionCode = permission.code
          tempPermission.permissionDesc = permission.desc
          tempPermission.menu = menu
          if (operatorUser) {
            tempPermission.createId = operatorUser.userId
            tempPermission.createBy = operatorUser.userName
          }
          permisssionEntity.push(this.permissionRepository.create(tempPermission))
        }
        console.log('permisssionEntity', permisssionEntity)
        await queryRunner.manager.insert(Permission, permisssionEntity)
      }

      const updatePermissions = buttons.filter((buttonItem) => {
        return !insertPermissions
          .map((permissionItem) => permissionItem.code)
          .includes(buttonItem.code)
      })

      if (updatePermissions.length) {
        const permissionRes = await this.permissionRepository.findBy({
          permissionCode: In(updatePermissions.map((item) => item.code)),
        })
        for (const permission of updatePermissions) {
          const tempPermission = await permissionRes.find(
            (resItem) => resItem.permissionCode === permission.code
          )
          tempPermission.permissionCode = permission.code
          tempPermission.permissionDesc = permission.desc
          if (operatorUser) {
            tempPermission.updateId = operatorUser.userId
            tempPermission.updateBy = operatorUser.userName
          }
          await queryRunner.manager.update(Permission, [tempPermission.id], tempPermission)
        }
      }
      await queryRunner.commitTransaction()
      // await queryRunner.commitTransaction()
      return '更新成功'
    } catch (error) {
      console.log('error', error.query)
      console.log('error', error.parameters)
      await queryRunner.rollbackTransaction()
      if (error.query.includes('DELETE FROM `t_sys_permission` WHERE `id` IN')) {
        const errorPermissions = await this.permissionRepository.find({
          where: {
            id: error.parameters[0],
          },
          relations: ['roles'],
        })
        const errorPermission = errorPermissions[0]
        const message = `按钮${errorPermission.permissionDesc}已经在${errorPermission.roles.splice(0, 3).map((item) => item.roleName)}等角色中被使用，无法修改按钮编码`
        throw new InternalServerErrorException(message)
      }
      throw new InternalServerErrorException(error)
    } finally {
      await queryRunner.release()
    }
  }

  async remove(ids: number[]) {
    // for (let i = 0; i < ids.length; i++) {
    //   const id = ids[i]
    //   const menu = await this.findOneById(id)
    //   const descendants = await this.menuRepository.findDescendants(menu)
    //   if (descendants?.length) {
    //     this.menuRepository.remove(descendants)
    //   }
    // }
    this.menuRepository.delete(ids)
    return `删除成功`
  }
}
